package com.jy.datapipeline.importserver.service.impl;

import com.jy.datapipeline.common.constants.PrefixConstants;
import com.jy.datapipeline.importserver.common.dto.ClientDto;
import com.jy.datapipeline.importserver.common.enums.impl.ExpEnum;
import com.jy.datapipeline.importserver.common.enums.impl.TaskStatusEnum;
import com.jy.datapipeline.common.exception.GlobalException;
import com.jy.datapipeline.common.vo.ReturnVo;
import com.jy.datapipeline.importserver.entity.ImportRetrySubtask;
import com.jy.datapipeline.importserver.entity.ImportSubtask;
import com.jy.datapipeline.importserver.entity.ImportTaskLog;
import com.jy.datapipeline.importserver.handler.ScheduleRetryHandler;
import com.jy.datapipeline.importserver.service.ImportRetrySubtaskService;
import com.jy.datapipeline.importserver.service.ImportServerService;
import com.jy.datapipeline.importserver.service.ImportSubTaskService;
import com.jy.datapipeline.importserver.support.MessageSupport;
import com.jy.datapipeline.importserver.support.QuartzSupport;
import lombok.extern.slf4j.Slf4j;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @类名 ServerServiceImpl
 * @描述 TODO
 * @作者 白条君
 * @创建日期 2023/6/22 23:55
 * @版本 1.0
 */
@Slf4j
@Service
public class ImportServerServiceImpl implements ImportServerService {

    private final MessageSupport messageSupport;

    private final ScheduleRetryHandler scheduleRetryHandler;

    private final QuartzSupport quartzSupport;

    private final ImportSubTaskService importSubTaskService;

    private final ImportRetrySubtaskService importRetrySubtaskService;

    public ImportServerServiceImpl(MessageSupport messageSupport,
                                   ScheduleRetryHandler scheduleRetryHandler,
                                   QuartzSupport quartzSupport,
                                   ImportSubTaskService importSubTaskService,
                                   ImportRetrySubtaskService importRetrySubtaskService) {
        this.messageSupport = messageSupport;
        this.scheduleRetryHandler = scheduleRetryHandler;
        this.quartzSupport = quartzSupport;
        this.importSubTaskService = importSubTaskService;
        this.importRetrySubtaskService = importRetrySubtaskService;
    }

    @Transactional
    @Override
    public synchronized ReturnVo retry(ClientDto clientDto) throws GlobalException {
        log.info("------ retry ------");
        long id = clientDto.getId();
        //修改子任务状态为失败
        messageSupport.modifySubTaskStatus(Collections.singleton(id), String.valueOf(TaskStatusEnum.VERIFY_FAIL.getCode()));
        //dat日志生成
        ImportTaskLog importTaskLog = clientDto.getImportTaskLog();
        messageSupport.createTaskLog(importTaskLog);
        //如果是文件大小异常或者记录行数异常执行重试操作,id为subtask的id
        Integer expCode = importTaskLog.getExpCode();
        if (ExpEnum.RECORDS_EXP.getCode().equals(expCode) || ExpEnum.FILE_SIZE_EXP.getCode().equals(expCode)) {
            return scheduleRetryHandler.executeRetry(id);
        }
        return null;
    }

    @Transactional
    @Override
    public synchronized void generateVerFailRetrySubtask(ClientDto clientDto) throws GlobalException, SchedulerException {
        long id = clientDto.getId();
        Set<Long> idSet = Collections.singleton(id);

        //ver日志生成
        messageSupport.createTaskLog(clientDto.getImportTaskLog());

        //修改子任务状态为重试失败或者执行失败
        ImportSubtask importSubtask = importSubTaskService.querySubtaskById(id);
        Integer trySubtaskLoadCurrentCount = importSubtask.getTrySubtaskLoadCurrentCount();
        Integer trySubtaskLoadCount = importSubtask.getTrySubtaskLoadCount();
        if (trySubtaskLoadCurrentCount == 0) {
            messageSupport.modifySubTaskStatus(idSet, String.valueOf(TaskStatusEnum.FAIL.getCode()));
        } else if (trySubtaskLoadCurrentCount < trySubtaskLoadCount) {
            messageSupport.modifySubTaskStatus(idSet, String.valueOf(TaskStatusEnum.RETRY_FAIL.getCode()));
        }

        //修改任务状态为异常
        if (!quartzSupport.isPaused(importSubtask.getTaskId())) {
            messageSupport.modifyTaskStatus(id, String.valueOf(TaskStatusEnum.EXCEPTION.getCode()));
        }

        //对无法获取的校验文件添加重试子任务
        if (trySubtaskLoadCurrentCount < trySubtaskLoadCount) {
            //更新子任务执行次数
            quartzSupport.createRetryScheduledTask(importSubtask.getStartTime(), id, importSubtask.getTrySubtaskLoadCount(), importSubtask.getTrySubtaskLoadInterval());
        }
    }

    @Override
    public synchronized void finish(ClientDto clientDto) throws GlobalException, SchedulerException {
        log.info("------ finish ------");
        //修改最终状态或者失败状态
        long id = clientDto.getId();
        Set<Long> idSet = Collections.singleton(id);
        //查询重试次数
        ImportSubtask importSubtask = importSubTaskService.querySubtaskById(id);
        Integer trySubtaskLoadCurrentCount = importSubtask.getTrySubtaskLoadCurrentCount();
        Integer trySubtaskLoadCount = importSubtask.getTrySubtaskLoadCount();
        if ("true".equals(clientDto.getIsSuccess())) {
            //修改子任务状态为重试成功或者执行成功
            if (trySubtaskLoadCurrentCount == 0) {
                messageSupport.modifySubTaskStatus(idSet, String.valueOf(TaskStatusEnum.SUCCESS.getCode()));
            } else if (trySubtaskLoadCurrentCount <= trySubtaskLoadCount) {
                messageSupport.modifySubTaskStatus(idSet, String.valueOf(TaskStatusEnum.RETRY_SUCCESS.getCode()));
            }
            //生成更新任务状态的定时器，单例创建
            messageSupport.updTaskStatus(id);
        } else if("false".equals(clientDto.getIsSuccess())) {
            if (!quartzSupport.isPaused(importSubtask.getTaskId())) {
                this.executeFailTask(trySubtaskLoadCurrentCount, trySubtaskLoadCount, idSet, importSubtask, id);
            }
        }
    }

    @Transactional
    public void executeFailTask(Integer trySubtaskLoadCurrentCount, Integer trySubtaskLoadCount, Set<Long> idSet, ImportSubtask importSubtask, long id) throws GlobalException, SchedulerException {
        Integer status = importSubTaskService.getSubtaskStatus(id);
        //修改子任务状态为重试失败或者执行失败
        if (!TaskStatusEnum.VERIFY_FAIL.getCode().equals(status)) {
            if (trySubtaskLoadCurrentCount == 0) {
                messageSupport.modifySubTaskStatus(idSet, String.valueOf(TaskStatusEnum.FAIL.getCode()));
            } else if (trySubtaskLoadCurrentCount <= trySubtaskLoadCount) {
                messageSupport.modifySubTaskStatus(idSet, String.valueOf(TaskStatusEnum.RETRY_FAIL.getCode()));
            }
        }

        //修改任务状态为异常
        messageSupport.modifyTaskStatus(id, String.valueOf(TaskStatusEnum.EXCEPTION.getCode()));

        //对导入失败的子任务添加重试子任务规则
        if (trySubtaskLoadCurrentCount < trySubtaskLoadCount && !TaskStatusEnum.VERIFY_FAIL.getCode().equals(status)) {
            quartzSupport.createRetryScheduledTask(importSubtask.getStartTime(), id, importSubtask.getTrySubtaskLoadCount(), importSubtask.getTrySubtaskLoadInterval());
        }
    }

    @Override
    public synchronized ReturnVo getRetrySubtask() throws GlobalException {
        List<ImportRetrySubtask> importRetrySubtasks = importRetrySubtaskService.queryUnExecutionRetrySubtasks();
        Set<String> retrySubtaskIds = importRetrySubtasks.stream().map(ImportRetrySubtask::getRetrySubtaskId).collect(Collectors.toSet());
        List<Long> ids = importRetrySubtasks.stream().map(ImportRetrySubtask::getSubtaskPrimaryKeyId).collect(Collectors.toList());
        List<ImportSubtask> importSubTasks = new ArrayList<>();
        for (Long id : ids) {
            ImportSubtask importSubTask = importSubTaskService.querySubtasksBySubtaskId(id);
            importSubTasks.add(importSubTask);
        }
        //批量更新重试子任务状态
        if (retrySubtaskIds.size() > 0) {
            importRetrySubtaskService.batchModifyRetrySubtaskStatus(retrySubtaskIds);
        }
        return ReturnVo.ok().put(importSubTasks);
    }

    @Override
    public void importSubtaskToSqlldr(ClientDto clientDto) throws GlobalException, SchedulerException {
        log.info("------ success or fail------");
        //dat日志生成
        messageSupport.createTaskLog(clientDto.getImportTaskLog());
        //删除重试定时任务
        if ("success".equals(clientDto.getFlag())) {
            quartzSupport.delete(PrefixConstants.SUBTASK_PREFIX + "_" + clientDto.getId(), "import_subtask");
        }
    }
}
